python 之 正则

前言:

之前打CTF经常性的因为不会写脚本而去手撸,这大大降低了效率,而且有的题由于时间限制,显然手撸行不通。

而不会写脚本经常是因为自己不会处理得到的数据,如何过滤、拼接。所以今天学习一下python的re模块,正则替换,以及刚刚从Li4n0学长脚本中发现的字符表替换。

正则

^元字符

字符串开始位置与匹配规则符合就匹配,否则不匹配

1
2
3
4
5
6
7
>>> import re
>>> result = re.findall("^匹配规则","匹配规则这个字符串是否匹配")
>>> print(result)
['匹配规则']
>>> result = re.findall("^匹配规则","匹配s规则这个字符串是否匹配")
>>> print(result)
[]

[^a-z]反取,

匹配出除字母外的字符,^元字符如果写到字符集里就是反取

1
2
3
4
>>> import re   #第一步,要引入re模块
>>> result = re.findall("[^a-z]", "匹配s规则这s个字符串是否s匹配f规则则re则则则") #反取,匹配出除字母外的字符
>>> print(result) #以列表形式返回匹配到的字符串
['匹', '配', '规', '则', '这', '个', '字', '符', '串', '是', '否', '匹', '配', '规', '则', '则', '则', '则', '则']

$元字符

字符串结束位置与匹配规则符合就匹配,否则不匹配

1
2
3
4
>>>import re   #第一步,要引入re模块
>>>a = re.findall("匹配规则$", "这个字符串是否匹配规则") #字符串结束位置与匹配规则符合就匹配,否则不匹配
>>>print(a) #以列表形式返回匹配到的字符串
['匹配规则']

*元字符

需要字符串里完全符合,匹配规则,就匹配,(规则里的*元字符)前面的一个字符可以是0个或多个原本字符

匹配前一个字符0或多次,贪婪匹配前导字符有多少个就匹配多少个很贪婪

如果规则里只有一个分组,尽量避免用*否则会有可能匹配出空字符串

1
2
3
4
5
6
7
8
9
10
>>> import re
>>> result = re.findall("匹配规则*","这个字符串是否匹配规则则则则则")
>>> print(result)
['匹配规则则则则则']
>>> result = re.findall("匹配规则*","这个字符串是否匹配规")
>>> print(result)
['匹配规']
>>> result = re.findall("匹配规则*","whether this string is matching?")
>>> print(result)
[]

+元字符

需要字符串里完全符合,匹配规则,就匹配,(规则里的+元字符)前面的一个字符可以是1个或多个原本字符

匹配前一个字符1次或无限次,贪婪匹配前导字符有多少个就匹配多少个很贪婪

1
2
3
4
>>> import re   #第一步,要引入re模块
>>> result = re.findall("匹配+", "匹配配配配配规则这个字符串是否匹配规则则则则则") #需要字符串里完全符合,匹配规则,就匹配,(规则里的+元字符)前面的一个字符可以是1个或多个原本字符
>>> print(result) #以列表形式返回匹配到的字符串
['匹配配配配配', '匹配']

?元字符,和防止贪婪匹配

需要字符串里完全符合,匹配规则,就匹配,(规则里的?元字符)前面的一个字符可以是0个或1个原本字符

匹配一个字符0次或1次

还有一个功能是可以防止贪婪匹配,详情见防贪婪匹配

1
2
3
4
>>> import re   #第一步,要引入re模块
>>> result = re.findall("匹配规则?", "匹配规这个字符串是否匹配规则则则则则") #需要字符串里完全符合,匹配规则,就匹配,(规则里的?元字符)前面的一个字符可以是0个或1个原本字符
>>> print(result) #以列表形式返回匹配到的字符串
['匹配规', '匹配规则']

.*?

1
2
3
4
5
6
7
8
9
>>> line = 'my title="sw engineer". His is "hello world"'
>>> m = re.search(r'title="(.*?)"', line)
>>> print m.group(1)
sw engineer

# 如果没有 ?, 则会抓到最长的两个双引号之间的内容
>>> m = re.search(r'title="(.*)"', line)
>>> print m.group(1)
sw engineer". His is "hello world

{}元字符,范围

需要字符串里完全符合,匹配规则,就匹配,(规则里的 {} 元字符)前面的一个字符,是自定义字符数,位数的原本字符

{m}匹配前一个字符m次,{m,n}匹配前一个字符m至n次,若省略n,则匹配m至无限次

{0,}匹配前一个字符0或多次,等同于*元字符
{+,}匹配前一个字符1次或无限次,等同于+元字符
{0,1}匹配前一个字符0次或1次,等同于?元字符

1
2
3
4
>>>import re   #第一步,要引入re模块
>>>result = re.findall("匹配规则{3}", "匹配规则这个字符串是否匹配规则则则则则") #{m}匹配前一个字符m次,{m,n}匹配前一个字符m至n次,若省略n,则匹配m至无限次
>>>print(result) #以列表形式返回匹配到的字符串
打印出 ['匹配规则则则']

[]元字符,字符集

需要字符串里完全符合,匹配规则,就匹配,(规则里的 [] 元字符)对应位置是[]里的任意一个字符就匹配

字符集。对应的位置可以是字符集中任意字符。字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c]。[^abc]表示取反,即非abc。所有特殊字符在字符集中都失去其原有的特殊含义。用\反斜杠转义 恢复 特殊字符的特殊含义。

1
2
3
4
5
6
7
>>> import re   #第一步,要引入re模块
>>> result = re.findall("匹配[a,b,c]规则", "匹配a规则这个字符串是否匹配b规则则则则则") #需要字符串里完全符合,匹配规则,就匹配,(规则里的 [] 元字符)对应位置是[]里的任意一个字符就匹配
>>> print(result) #以列表形式返回匹配到的字符串
['匹配a规则', '匹配b规则']
>>> result = re.findall("匹配[a,b,c]规则\t", "匹配a规则 这个字符串是否匹配b规则则则则则")
>>> print(result)
['匹配a规则\t']

反斜杠后边跟普通字符实现特殊功能;(即预定义字符)

预定义字符是在字符集和组里都是有用的

\d匹配任何十进制数,它相当于类[0-9]

1
2
3
4
>>> import re   #第一步,要引入re模块
>>> result = re.findall("\d", "匹配规则这2个字符串33是否匹配规则5则则则7则") #\d匹配任何十进制数,它相当于类[0-9]
>>> print(result) #以列表形式返回匹配到的字符串
['2', '3', '3', '5', '7']

\d+如果需要匹配一位或者多位数的数字时用

1
2
3
4
>>> import re   #第一步,要引入re模块
>>> result = re.findall("\d", "匹配规则这2个字符串33是否匹配规则5则则则7则") #\d匹配任何十进制数,它相当于类[0-9]
>>> print(result) #以列表形式返回匹配到的字符串
['2', '33', '5', '7']

\D匹配任何非数字字符,它相当于类[^0-9]

1
2
3
4
>>> import re   #第一步,要引入re模块
>>> result = re.findall("\D", "匹配规则这2个字符串33是否匹配规则5则则则7则") #\D匹配任何非十进制数,它相当于类[^0-9]
>>> print(result) #以列表形式返回匹配到的字符串
['匹', '配', '规', '则', '这', '个', '字', '符', '串', '是', '否', '匹', '配', '规', '则', '则', '则', '则', '则']

\s匹配任何空白字符,它相当于类[\t\n\r\f\v]

1
2
3
4
>>> import re   #第一步,要引入re模块
>>> result = re.findall("\s", "匹配规则 这2个字符串3是否匹\n配规则5则则则7则") #\s匹配任何空白字符,它相当于类[\t\n\r\f\v] (横向制表符、换行、回车、换页、纵向制表符)
>>> print(result) #以列表形式返回匹配到的字符串
['\t', ' ', ' ', '\n']

\S匹配任何非空白字符,它相当于类[^\t\n\r\f\v]

1
2
3
4
>>> import re   #第一步,要引入re模块
>>> result = re.findall("\S", "匹配规则 这2个字符串3是否匹\n配规则5则则则7则") #\S匹配任何非空白字符,它相当于类[^\t\n\r\f\v] (横向制表符、换行、回车、换页、纵向制表符)
>>> print(result) #以列表形式返回匹配到的字符串
['匹', '配', '规', '则', '这', '2', '个', '字', '符', '串', '3', '是', '否', '匹', '配', '规', '则', '5', '则', '则', '则', '7', '则']

\w匹配包括下划线在内任何字母数字字符,它相当于类[a-zA-Z0-9_]

1
2
3
4
>>> import re   #第一步,要引入re模块
>>> result = re.findall('\w',"https://www.cnblogs.com/") #\w匹配包括下划线在内任何字母数字字符,它相当于类[a-zA-Z0-9_]
>>> print(result) #以列表形式返回匹配到的字符串
['h', 't', 't', 'p', 's', 'w', 'w', 'w', 'c', 'n', 'b', 'l', 'o', 'g', 's', 'c', 'o', 'm']

\W匹配非任何字母数字字符包括下划线在内,它相当于类[^a-zA-Z0-9_]

1
2
3
4
>>> import re   #第一步,要引入re模块
>>> result = re.findall('\W',"https://www.cnblogs.com/") #\W不匹配包括下划线在内任何字母数字字符,它相当于类[^a-zA-Z0-9_]
>>> print(result) #以列表形式返回匹配到的字符串
[':', '/', '/', '.', '.', '/']

()元字符,分组

也就是分组匹配,()里面的为一个组也可以理解成一个整体

如果()后面跟的是特殊元字符如 (adc)* 那么*控制的前导字符就是()里的整体内容,不再是前导一个字符

1
2
3
4
5
6
7
8
9
10
11
12
>>> import re   #第一步,要引入re模块
#也就是分组匹配,()里面的为一个组也可以理解成一个整体
>>> result = re.search("(a4)+", "a4a4a4a4a4dg4g654gb") #匹配一个或多个a4
>>> result1 = result.group()
>>> print(result1)
a4a4a4a4a4
>>> result = re.search("a(\d+)","a45646148a49a4a456048a45gg")
>>> print(result)
<re.Match object; span=(0, 9), match='a45646148'>
>>> result1 = result.group()
>>> print(result1)
a45646148

|元字符,或

|或,或就是前后其中一个符合就匹配

1
2
3
4
5
6
7
>>> import re   #第一步,要引入re模块
>>> result = re.findall(r"你|好", "a4a4a你4aabc4a4dgg好dg4g654g") #|或,或就是前后其中一个符合就匹配
>>> print(result)
['你', '好']
>>> result = re.findall(r"a4a4a你|好dg4g654","a4a4a你4aabc4a4dgg好dg4g654g")
>>> print(result)
['a4a4a你', '好dg4g654']

r原生字符

将在python里有特殊意义的字符如\b,转换成原生字符(就是去除它在python的特殊意义),不然会给正则表达式有冲突,为了避免这种冲突可以在规则前加原始字符r

(这里还有点问题,结果不太懂,为啥第一个不输出 [a\b] )

1
2
3
4
5
6
7
>>> import re   #第一步,要引入re模块
>>> result = re.findall(r"a\b","welcoma\b")
>>> print(result)
['a']
>>> result = re.findall("a\b","welcoma\b")
>>> print(result)
['a\x08']

Re

result = re.method(“rule”,string)

1. match()方法, 从字符串头部开始匹配

1
2
3
4
5
6
7
8
import re

content = 'The 123456 is my one phone number.'
print(len(content)) #字符串长度
result = re.match(r'^The\s\d+\s\w*', content) #使用match匹配, 第一个参数为正则表达式, 第二个为要匹配的字符串
print(result)
print(result.group()) #输出匹配内容
print(result.span()) #输出匹配内容的位置索引

结果:

1
2
3
4
34
<_sre.SRE_Match object; span=(0, 13), match='The 123456 is'>
The 123456 is
(0, 13)

2. 匹配目标

在正则表达式中用()括起来可以使用group()输出, 若有n个(), 那么可以表示为group(n), 输出第n个括号匹配的内容.

1
2
3
4
5
6
7
8
9
import re

content = 'The 123456 is my one phone number.'
print(len(content)) #字符串长度
result = re.match(r'^The\s(\d+)\sis', content) #使用match匹配, 第一个参数为正则表达式, 第二个为要匹配的字符串
print(result)
print(result.group()) #输出匹配内容
print(result.group(1)) #输出第一个被()包裹的内容
print(result.span()) #输出匹配内容的位置索引

结果

1
2
3
4
5
34
<_sre.SRE_Match object; span=(0, 13), match='The 123456 is'>
The 123456 is
123456
(0, 13)

3.通用匹配

. 表示匹配任意字符, *表示匹配前面字符无限次.

1
2
3
4
5
6
7
import re

content = 'The 123456 is my one phone number.'
result = re.match(r'^The.*number.$', content) #使用match匹配, 第一个参数为正则表达式, 第二个为要匹配的字符串
print(result)
print(result.group()) #输出匹配内容
print(result.span()) #输出匹配内容的位置索引

结果

1
2
3
<_sre.SRE_Match object; span=(0, 34), match='The 123456 is my one phone number.'>
The 123456 is my one phone number.
(0, 34)

4.贪婪与非贪婪

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import re

content = 'The 123456 is my one phone number.'
print('贪婪匹配:')
result = re.match(r'^The.*(\d+).*', content) #使用match匹配, 第一个参数为正则表达式, 第二个为要匹配的字符串
print(result.group()) #输出匹配内容
print('result = %s'%result.group(1)) #输出第一个被()包裹的内容
print('-'*20)
print('非贪婪匹配:')
result = re.match(r'^The.*?(\d+).*', content)
print(result.group())
print('result = %s'%result.group(1))
print('-'*20)
result = re.match(r'^The.*?(\d+).*?', content)
print(result.group())

结果

1
2
3
4
5
6
7
8
9
贪婪匹配:
The 123456 is my one phone number.
result = 6
--------------------
非贪婪匹配:
The 123456 is my one phone number.
result = 123456
--------------------
The 123456

5.修饰符 re.S

由于加上re.S参数后, 通配符 . 将可以匹配换行符, 所以result不为空, result2为空。除了re.S, 还有许多修饰符如,

re.I: 使用匹配时忽略大小写。(大写的i)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import re

content = '''The 123456 is
one of my phone.
'''
result = re.match('^The.*?(\d+).*?phone.', content, re.S)
if result:
print(result.group(1))
else:
print('result = None')
result2 = re.match('^The.*?(\d+).*?phone.', content)
if result2:
print(result2.group(1))
else:
print('result2 = None')

结果

1
2
123456
result2 = None

6.转义匹配

由于()属于正则表达式的特殊字符, 因此在需要匹配()时, 需要加上转义字符’’.

1
2
3
4
5
6
7
8
9
10
11
12
13
import re

content = '(百度)www.baidu.com'
result = re.match('(百度)www.baidu.com', content)
result2 = re.match('\(百度\)www\.baidu\.com', content)
if result:
print(result.group())
else:
print('result = None')
if result2:
print(result2.group())
else:
print('result2 = None')

结果

1
2
result = None
(百度)www.baidu.com

7.search()方法, 与match()方法不同, 不需要从头部开始匹配

1
2
3
4
5
import re

content = 'Other The 123456 is my one phone number.'
result = re.search('The.*?(\d+).*?number.', content)
print(result.group())

结果

1
The 123456 is my one phone number.

8.findall()方法

match()和search()都是返回匹配到的第一个内容就结束匹配, findall()是返回所有符合匹配规则的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import re

html = '''
<div id="songs-list">
<h2 class="title">歌单</h2>
<p class="introduction">歌单列表</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="程慧玲">记事本</a></li>
<li data-veiw="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>
'''

result = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S)
if result:
print(result)
for res in result:
print(res[0], res[1], res[2])

结果

1
2
3
4
5
6
[('/2.mp3', '任贤齐', '沧海一声笑'), ('/3.mp3', '齐秦', '往事随风'), ('/4.mp3', 'beyond', '光辉岁月'), ('/5.mp3', '程慧玲', '记事本'), ('/6.mp3', '邓丽君', '但愿人长久')]
/2.mp3 任贤齐 沧海一声笑
/3.mp3 齐秦 往事随风
/4.mp3 beyond 光辉岁月
/5.mp3 程慧玲 记事本
/6.mp3 邓丽君 但愿人长久

9.sub()方法, 去除匹配的字符

第二个参数是两个’,表示吧’\d+‘ 匹配的内容替换成空,如果写sub(’\d+’, ‘?’), 则把匹配的内容替换成 ?。

1
2
3
4
5
6
7
8
9
import re

content = '54abc59de335f7778888g'
result = re.sub('\d+', '', content)
print(result)
result = re.sub('\d', '?', content)
print(result)
result = re.sub('\d+', '?', content)
print(result)

结果

1
2
3
abcdefg
??abc??de???f???????g
?abc?de?f?g

有点像replace,但是多一个正则关系匹配

10.compile()

在需要匹配相同正则表达式情况下, 事先定义一个compile可以简化代码量, 同时compile中也可以使用修饰符re.S等.

( 其实也可以直接a=rule,然后 result = re.findall(a,string) ,但是这样子就不能用修饰符re.S了)

1
2
3
4
5
6
7
8
9
10
11
import re

content1 = '2016-1-1 12:01'
content2 = '2017-1-1 12:02'
content3 = '2018-1-1 12:03'

pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern, '', content1)
result2 = re.sub(pattern, '', content2)
result3 = re.sub(pattern, '', content3)
print(result1, result2, result3)

结果

1
2016-1-1  2017-1-1  2018-1-1

附一手去除列表空元素的方法:

1
mytest = [i for i in test if i != '']

番外

这里记一下从从Li4n0学长脚本中发现的字符表替换函数:maketrans()

语法:str.maketrans(intab, outtab)

参数:

intab – 字符串中要替代的字符组成的字符串

outtab – 相应的映射字符的字符串。

配合str.translate使用

实例

1
2
3
4
5
6
intab = "aeiou"
outtab = "4310U"
transtab = str.maketrans(intab, outtab)

content = "this is string example....wow!!!"
print (content.translate(transtab))

结果

1
th1s 1s str1ng 3x4mpl3....w0w!!!

参考资料:

https://blog.csdn.net/qq_38038143/article/details/80671420

https://www.cnblogs.com/zjltt/p/6955965.html


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可联系QQ 643713081,也可以邮件至 643713081@qq.com

文章标题:python 之 正则

文章字数:4.4k

本文作者:Van1sh

发布时间:2019-07-21, 22:30:35

最后更新:2020-05-24, 18:32:54

原始链接:http://jayxv.github.io/2019/07/21/python 正则/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏